package cn.esbot.wx.mp.client;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.catalina.util.URLEncoder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class EsbotTemplate {
    private String appId;
    private String appKey;
    private String robotUrl;
    private StringRedisTemplate redisTemplate;
    private final String WX_MP_PREFIX = "esbot:weixin:mp:session:";

    public String chat(String question, String formUsername, String username, String region) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("question", question);
        paramMap.put("timestamp", System.currentTimeMillis());
        paramMap.put("appId", appId);
        paramMap.put("sign", getSignature(paramMap, appKey));
        paramMap.put("channel", "公众号");
        paramMap.put("username", username);
        paramMap.put("region", region);
        //noinspection ConstantConditions
        if (StringUtils.hasText(formUsername) && redisTemplate.hasKey(formUsername)) {
            headers.add("Cookie", redisTemplate.opsForValue().get(formUsername));

        }
        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(robotUrl, httpEntity, String.class);
        List<String> cookie = responseEntity.getHeaders().get("Set-Cookie");
        if (!CollectionUtils.isEmpty(cookie) && StringUtils.hasText(formUsername)) {
            String jsession = cookie.parallelStream()
                    .filter(s -> s.contains("JSESSIONID"))
                    .collect(Collectors.joining());
            String[] sessionArr = jsession.split(";");
            if (sessionArr.length > 0) {
                for (String s : sessionArr) {
                    if (s.contains("JSESSIONID")) {
                        redisTemplate.opsForValue().set(WX_MP_PREFIX + formUsername, s, 30L, TimeUnit.MINUTES);
                        break;
                    }
                }
            }
        }
        JSONObject response = JSON.parseObject(responseEntity.getBody());
        if (response.getIntValue("code") == 0) {
            return response.getJSONObject("data").getString("answer");
        }
        return null;
    }

    private String getSignature(Map<String, Object> params, String appKey) {
        Map<String, Object> sortedParams = new TreeMap<>(params);
        Set<Map.Entry<String, Object>> entrys = sortedParams.entrySet();
        StringBuilder baseString = new StringBuilder();
        for (Map.Entry<String, Object> param : entrys) {
            if (param.getValue() != null && !"".equals(param.getKey().trim()) &&
                    !"sign".equals(param.getKey().trim()) && !"".equals(param.getValue())) {
                baseString.append(param.getKey().trim()).append("=")
                        .append(URLEncoder.DEFAULT.encode(param.getValue().toString(), StandardCharsets.UTF_8)).append("&");
            }
        }
        if (baseString.length() > 0) {
            baseString.deleteCharAt(baseString.length() - 1).append("&appKey=")
                    .append(appKey);
        }
        String sign = DigestUtils.md5DigestAsHex(baseString.toString().getBytes());
        return sign.toUpperCase();
    }

}
